package com.regent.central.bill.service.bean;

import com.github.pagehelper.PageHelper;
import com.regent.central.bill.common.ActionType;
import com.regent.central.bill.core.SaleOrder;
import com.regent.central.bill.core.SaleOrderAction;
import com.regent.central.bill.dto.sale_order.*;
import com.regent.central.bill.repository.OddmentLoggingMapper;
import com.regent.central.bill.repository.SaleOrderActionMapper;
import com.regent.central.bill.repository.SaleOrderMapper;
import com.regent.central.bill.service.SaleOrderActionService;
import com.regent.central.infrastructure.common.OrderAs;
import com.regent.central.infrastructure.service.bean.DomainServiceBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;

@Service
public class SaleOrderActionServiceBean extends DomainServiceBean<SaleOrderActionMapper, SaleOrderAction> implements SaleOrderActionService {

    @Autowired
    private SaleOrderMapper saleOrderMapper;

    @Autowired
    private OddmentLoggingMapper oddmentLoggingMapper;

    /**
     * 获取销售单的操作记录列表
     *
     * @param saleOrderId     销售单ID
     * @param startSearchTime 开始搜索时间
     * @param orderBy         排序字段
     * @param orderAs         排序方式
     * @param pageNo          页码
     * @param pageSize        每页最大条数
     * @return 销售单的操作记录列表
     */
    @Override
    public List<SaleOrderActionDTO> getPagedSaleOrderActions(String saleOrderId, String startSearchTime, String orderBy, OrderAs orderAs, int pageNo, int pageSize) {
        // 分页
        PageHelper.startPage(pageNo, pageSize);
        // 操作记录主记录
        List<SaleOrderActionDTO> actions = mapper.getSaleOrderActions(
                saleOrderId,
                startSearchTime,
                orderBy,
                orderAs == null ? null : orderAs.name()
        );
        // 如果没有记录
        if (actions == null || actions.isEmpty()) {
            return Collections.emptyList();
        }

        // 分组
        Map<ActionType, Map<String, SaleOrderActionDTO>> map = new HashMap<>();
        actions.forEach(action -> {
            ActionType actionType = action.getActionType();
            if (map.containsKey(actionType)) {
                map.get(actionType).put(action.getActionId(), action);
            }
            else {
                map.put(actionType, new HashMap<>(Collections.singletonMap(action.getActionId(), action)));
            }
        });

        // 分别查询
        map.forEach((actionType, group) -> {
            switch (actionType) {
                case ODDMENT:
                    BigDecimal oddment = saleOrderMapper.getOddment(saleOrderId);
                    List<SaleOrderActionOddmentLoggingDTO> oddmentLoggings = oddmentLoggingMapper.getSaleOrderActionOddmentLoggings(saleOrderId);
                    group.values().forEach(action -> {
                        action.setOddment(oddment);
                        action.setOddmentLoggings(oddmentLoggings);
                    });
                    break;
                case REMITTANCE:
                    mapper.getSaleOrderActionRemittancesIn(group.keySet().toArray(new String[0])).forEach(remittance -> group.get(remittance.getActionId()).setRemittance(remittance));
                    break;
                case CREATE:
                    mapper.getSaleOrderActionCreateGoodsParentIn(group.keySet().toArray(new String[0])).forEach(goods -> {
                        calculate(goods);
                        SaleOrderActionGoodsSetDTO goodsSet = group.get(goods.getParentId()).getGoodsSet();
                        goodsSet.getGoods().add(goods);
                        goodsSet.setTotal(goodsSet.getTotal().add(goods.getTotalModified()));
                        goodsSet.setAmount(goodsSet.getAmount().add(goods.getAmountModified()));
                    });
                    break;
                case MODIFY_THAT:
                    group.values().forEach(action -> {action.getGoodsSet().setSaleOrderId(action.getDataId());
                        SaleOrder saleOrder = saleOrderMapper.selectByPrimaryKey(action.getDataId());
                        action.setOrderDay(saleOrder.getOrderDay());
                        action.setOrderNo(saleOrder.getOrderNo());
                    });
                    mapper.getSaleOrderActionModifyGoodsParentIn(group.keySet().toArray(new String[0])).forEach(goods -> {
                        calculate(goods);
                        SaleOrderActionGoodsSetDTO goodsSet = group.get(goods.getParentId()).getGoodsSet();
                        goodsSet.getGoods().add(goods);
                        goodsSet.setTotalModified(goodsSet.getTotalModified().add(goods.getTotalModified()));
                        goodsSet.setTotalModifiedInc(goodsSet.getTotalModifiedInc().add(goods.getTotalModifiedInc()));
                        goodsSet.setTotalModifiedDec(goodsSet.getTotalModifiedDec().add(goods.getTotalModifiedDec()));
                        goodsSet.setTotal(goodsSet.getTotal().add(goods.getTotalModified()));
                        goodsSet.setAmount(goodsSet.getAmount().add(goods.getAmountModified()));
                    });
                    break;
                case MODIFY_THIS:
                    group.values().forEach(action -> {action.getGoodsSet().setSaleOrderId(action.getDataId());
                        SaleOrder saleOrder = saleOrderMapper.selectByPrimaryKey(action.getDataId());
                        action.setOrderDay(saleOrder.getOrderDay());
                        action.setOrderNo(saleOrder.getOrderNo());
                    });
                    mapper.getSaleOrderActionModifyGoodsParentIn(group.keySet().toArray(new String[0])).forEach(goods -> {
                        calculate(goods);
                        SaleOrderActionGoodsSetDTO goodsSet = group.get(goods.getParentId()).getGoodsSet();
                        goodsSet.getGoods().add(goods);
                        goodsSet.setTotalModified(goodsSet.getTotalModified().add(goods.getTotalModified()));
                        goodsSet.setTotalModifiedInc(goodsSet.getTotalModifiedInc().add(goods.getTotalModifiedInc()));
                        goodsSet.setTotalModifiedDec(goodsSet.getTotalModifiedDec().add(goods.getTotalModifiedDec()));
                        goodsSet.setTotal(goodsSet.getTotal().add(goods.getTotalModified()));
                        goodsSet.setAmount(goodsSet.getAmount().add(goods.getAmountModified()));
                    });
                    break;
                case RETURN:
                    mapper.getSaleOrderActionReturnGoodsParentIn(group.keySet().toArray(new String[0])).forEach(goods -> {
                        calculate(goods);
                        SaleOrderActionGoodsSetDTO goodsSet = group.get(goods.getParentId()).getGoodsSet();
                        goodsSet.getGoods().add(goods);
                        goodsSet.setTotal(goodsSet.getTotal().add(goods.getTotalModified()));
                        goodsSet.setAmount(goodsSet.getAmount().add(goods.getAmountModified()));
                    });
                    break;
                case DELIVERY:
                    mapper.getSaleOrderActionDeliveriesParentIn(group.keySet().toArray(new String[0])).forEach(delivery -> {
                        group.get(delivery.getParentId()).setDelivery(delivery);
                        delivery.getGoods().forEach(goods -> {
                            BigDecimal total = goods.getSkus().stream().map(SaleOrderActionDeliveryGoodsSKUDTO::getQuantity).reduce(BigDecimal::add).orElse(BigDecimal.ZERO);
                            goods.setTotal(total);
                        });
                    });
                    break;
                case CLEARANCE_IN:
                    mapper.getSaleOrderActionInClearancesIn(group.keySet().toArray(new String[0])).forEach(clearance -> group.get(clearance.getActionId()).setClearance(clearance));
                    break;
                case CLEARANCE_OUT:
                    mapper.getSaleOrderActionOutClearancesIn(group.keySet().toArray(new String[0])).forEach(clearance -> group.get(clearance.getActionId()).setClearance(clearance));
                    break;
            }
        });

        return actions;
    }

    /**
     * 计算增加/减少的SKU数量/金额
     *
     * @param goods 货品
     */
    private void calculate(SaleOrderActionGoodsDTO goods) {
        BigDecimal totalModifiedInc = goods.getSkus().stream()
                .filter(sku -> sku.getQuantity() != null)
                .filter(sku -> sku.getQuantity().compareTo(BigDecimal.ZERO) > 0)
                .map(SaleOrderActionGoodsSKUDTO::getQuantity)
                .reduce(BigDecimal::add)
                .orElse(BigDecimal.ZERO);
        BigDecimal totalModifiedDec = goods.getSkus().stream()
                .filter(sku -> sku.getQuantity() != null)
                .filter(sku -> sku.getQuantity().compareTo(BigDecimal.ZERO) < 0)
                .map(SaleOrderActionGoodsSKUDTO::getQuantity)
                .reduce(BigDecimal::add)
                .orElse(BigDecimal.ZERO);
        goods.setTotalModified(totalModifiedInc.add(totalModifiedDec));
        goods.setTotalModifiedInc(totalModifiedInc);
        goods.setTotalModifiedDec(totalModifiedDec);

        BigDecimal amountModifiedInc = goods.getSkus().stream()
                .filter(sku -> sku.getQuantity() != null)
                .filter(sku -> sku.getPrice() != null)
                .filter(sku -> sku.getQuantity().compareTo(BigDecimal.ZERO) > 0)
                .map(sku -> sku.getQuantity().multiply(sku.getPrice()))
                .reduce(BigDecimal::add)
                .orElse(BigDecimal.ZERO);
        BigDecimal amountModifiedDec = goods.getSkus().stream()
                .filter(sku -> sku.getQuantity() != null)
                .filter(sku -> sku.getPrice() != null)
                .filter(sku -> sku.getQuantity().compareTo(BigDecimal.ZERO) < 0)
                .map(sku -> sku.getQuantity().multiply(sku.getPrice()))
                .reduce(BigDecimal::add)
                .orElse(BigDecimal.ZERO);
        goods.setAmountModified(amountModifiedInc.add(amountModifiedDec));
        goods.setAmountModifiedInc(amountModifiedInc);
        goods.setAmountModifiedDec(amountModifiedDec);
    }

    /**
     * 撤销销售单动作
     *
     * @param saleOrderActionId 销售单动作ID
     * @param userCanceled      撤销人
     */
    @Override
    public void cancel(String saleOrderActionId, String userCanceled) {
        mapper.cancel(saleOrderActionId, userCanceled, new Date());
    }

    /**
     * 撤销销售单动作
     *
     * @param saleOrderActionId 销售单动作ID
     * @param userCanceled      撤销人
     */
    @Override
    public void cancelChildren(String saleOrderActionId, String userCanceled) {
        mapper.cancelChildren(saleOrderActionId, userCanceled, new Date());
    }

    /**
     * 根据动作的数据ID和动作类型查询销售单动作记录
     *
     * @param actionType 动作类型
     * @param actionId   动作数据ID
     * @return 销售单动作记录
     */
    @Override
    public SaleOrderAction selectBy(ActionType actionType, String actionId) {
        return mapper.selectBy(actionType, actionId);
    }

    /**
     * 根据销售单ID和动作类型查询销售单动作
     *
     * @param saleOrderId 销售单ID
     * @param actionType  动作类型
     * @return 销售单动作
     */
    @Override
    public SaleOrderAction selectByOrderIdAndActionType(String saleOrderId, ActionType actionType) {
        PageHelper.startPage(1, 1);
        return mapper.selectByOrderIdAndActionType(saleOrderId, actionType);
    }

    /**
     * 根据销售单ID和动作类型查询销售单动作
     *
     * @param saleOrderId 销售单ID
     * @param actionType  动作类型
     * @return 销售单动作
     */
    @Override
    public List<SaleOrderAction> listByOrderIdAndActionType(String saleOrderId, ActionType actionType) {
        return mapper.listByOrderIdAndActionType(saleOrderId, actionType);
    }

    /**
     * 获取销售单的某个发货单的发货货品动作记录
     *
     * @param saleOrderId 销售单ID
     * @param deliveryId  发货单ID
     * @return 该销售单的某个发货单的发货货品动作记录
     */
    @Override
    public List<SaleOrderAction> getSaleOrderDeliveryGoodsActions(String saleOrderId, String deliveryId) {
        return mapper.getSaleOrderDeliveryGoodsActions(saleOrderId, deliveryId);
    }

    /**
     * 根据销售单ID和actionId进行撤销操作
     *
     * @param actionType 动作类型
     * @param actionIds  动作ID
     */
    @Override
    public void cancel(ActionType actionType, String userCanceled, String... actionIds) {
        if (actionIds.length == 0) {return;}
        mapper.cancelActions(actionType, userCanceled, actionIds);
    }

    /**
     * 获取 actiontype为 Delivery 的 actionId
     *
     * @param deliveryOrderId
     * @return
     */
    @Override
    public List<SaleOrderAction> getSaleOrderDeliveryActions(String deliveryOrderId) {
        return mapper.getSaleOrderDeliveryActions(deliveryOrderId);
    }

    /**
     * 获取销售单动作列表
     *
     * @param saleOrderId 销售单ID
     * @param parent      是否是父动作
     * @return 销售单动作列表
     */
    @Override
    public List<SaleOrderAction> getSaleOrderAllActions(String saleOrderId, Boolean parent) {
        return getSaleOrderAllActions(saleOrderId, parent, false, false);
    }

    /**
     * 获取销售单动作列表
     *
     * @param saleOrderId 销售单ID
     * @param parent      是否是父动作
     * @param canceled    已撤销
     * @param deleted     已删除
     * @return 销售单动作列表
     */
    @Override
    public List<SaleOrderAction> getSaleOrderAllActions(String saleOrderId, Boolean parent, Boolean canceled, Boolean deleted) {
        return mapper.getSaleOrderAllActions(saleOrderId, parent, canceled, deleted);
    }
}